import msgspec
from clang.cindex import Cursor, CursorKind, LinkageKind

from .ctyper import CtypeTranslater, set_unnamed_var_name

ctype_translater = CtypeTranslater()


class CType(msgspec.Struct):
    declaration: Cursor
    definition: Cursor | None

    def __repr__(self):
        return f"{set_unnamed_var_name(self.declaration)}"


class Decl(msgspec.Struct):
    declaration: Cursor
    depend_types: list[CType]
    depend_decls: set["Decl"] = msgspec.field(default_factory=lambda: set())

    @property
    def hash(self): return self.declaration.hash

    def __repr__(self):
        return self.print_declaration() + self.print_definition()

    def get_decl_name(self):
        return set_unnamed_var_name(self.declaration)

    def parse(self, maker):
        pass

    def print_declaration(self):
        return ""

    def print_definition(self):
        return f"{self.get_decl_name()} = {ctype_translater.translate(self.declaration.type)}\n"

    def __hash__(self):
        return self.hash

    def __eq__(self, other):
        return self.hash == other.hash


class UNEXPOSED_DECL(Decl):
    def parse(self, maker):
        for item in self.declaration.get_children():
            decl = maker.dispatch_decl(item)
            if decl:
                self.depend_decls.add(decl)


class STRUCT_DECL(Decl):
    _pack: int = 1

    def parse(self, maker):
        if self.declaration.is_definition():
            self._pack = self.declaration.type.get_align()
            for field in self.declaration.get_children():
                decl = maker.dispatch_decl(field)
                if decl and field.kind in (CursorKind.FIELD_DECL, ):
                    self.depend_decls.add(decl)

    def print_declaration(self):
        return f"""# {self.declaration.location}
class {self.get_decl_name()}(ct.Structure): pass
"""

    def print_definition(self):
        return f"""{self.get_decl_name()}._fields_ = [
{"\n".join([field.print_definition() for field in self.depend_decls])}
]
"""

class UNION_DECL(STRUCT_DECL):
    def print_declaration(self):
        return f"""# {self.declaration.location}
class {self.get_decl_name()}(ct.Union): pass
"""


class FIELD_DECL(Decl):
    _is_bit_field: bool = False
    _bit_field_width: int = 0

    def parse(self, maker):
        self._is_bit_field = self.declaration.is_bitfield()
        if self._is_bit_field:
            self._bit_field_width = self.declaration.type.get_size()

    def print_definition(self):
        if self._is_bit_field:
            return f"\t('{self.get_decl_name()}', {ctype_translater.translate(self.declaration.type.get_canonical())}, {self._bit_field_width}),"
        else:
            return f"\t('{self.get_decl_name()}', {ctype_translater.translate(self.declaration.type.get_canonical())}),"


class TYPEDEF_DECL(Decl):
    def print_definition(self):
        a, b = self.get_decl_name(), ctype_translater.translate(self.declaration.type.get_canonical())
        if a != b:
            return f"{a} = {b}\n"

class ENUM_DECL(Decl): pass

class FUNCTION_DECL(Decl):
    def print_definition(self):
        return f"""# {self.declaration.location}
# {self.declaration.linkage}
{super().print_definition()}
"""

    @property
    def is_external(self):
        return self.declaration.linkage == LinkageKind.EXTERNAL

    def parse(self, maker):
        pass